/**
 * 安全沙箱实现
 * 替换不安全的 vm2 库
 */

import { logger } from '../../utils/logger';
import { PluginError } from '../../utils/error-handler';

export interface SandboxOptions {
  timeout?: number;
  memoryLimit?: number;
  allowedGlobals?: string[];
  allowedModules?: string[];
}

export interface SandboxResult<T = unknown> {
  success: boolean;
  result?: T;
  error?: string;
  executionTime: number;
  memoryUsed: number;
}

/**
 * 安全沙箱类
 * 使用 Web Workers 和严格的权限控制替代 vm2
 */
export class SecureSandbox {
  private options: Required<SandboxOptions>;
  private worker?: Worker;

  constructor(options: SandboxOptions = {}) {
    this.options = {
      timeout: options.timeout ?? 5000,
      memoryLimit: options.memoryLimit ?? 50 * 1024 * 1024, // 50MB
      allowedGlobals: options.allowedGlobals ?? ['console', 'setTimeout', 'clearTimeout'],
      allowedModules: options.allowedModules ?? [],
    };
  }

  /**
   * 执行代码
   */
  async execute<T = unknown>(code: string, context: Record<string, unknown> = {}): Promise<SandboxResult<T>> {
    const startTime = performance.now();
    const startMemory = this.getMemoryUsage();

    try {
      // 验证代码安全性
      this.validateCode(code);

      // 创建安全执行环境
      const result = await this.executeInSafeEnvironment<T>(code, context);

      const endTime = performance.now();
      const endMemory = this.getMemoryUsage();

      return {
        success: true,
        result,
        executionTime: endTime - startTime,
        memoryUsed: endMemory - startMemory,
      };
    } catch (error) {
      const endTime = performance.now();
      const endMemory = this.getMemoryUsage();

      logger.error('Sandbox execution failed:', error as Error);

      return {
        success: false,
        error: (error as Error).message,
        executionTime: endTime - startTime,
        memoryUsed: endMemory - startMemory,
      };
    }
  }

  /**
   * 验证代码安全性
   */
  private validateCode(code: string): void {
    // 检查危险函数调用
    const dangerousPatterns = [
      /eval\s*\(/,
      /Function\s*\(/,
      /setTimeout\s*\(\s*["'`][^"'`]*["'`]/,
      /setInterval\s*\(\s*["'`][^"'`]*["'`]/,
      /document\./,
      /window\./,
      /global\./,
      /process\./,
      /require\s*\(/,
      /import\s*\(/,
      /__dirname/,
      /__filename/,
      /fs\./,
      /path\./,
      /os\./,
      /child_process/,
      /cluster/,
      /crypto\.randomBytes/,
    ];

    for (const pattern of dangerousPatterns) {
      if (pattern.test(code)) {
        throw new PluginError(`Dangerous code pattern detected: ${pattern.source}`);
      }
    }

    // 检查代码长度
    if (code.length > 100000) {
      throw new PluginError('Code too long');
    }

    // 检查嵌套深度
    const maxDepth = 10;
    let depth = 0;
    let maxDepthFound = 0;

    for (const char of code) {
      if (char === '{' || char === '(' || char === '[') {
        depth++;
        maxDepthFound = Math.max(maxDepthFound, depth);
      } else if (char === '}' || char === ')' || char === ']') {
        depth--;
      }
    }

    if (maxDepthFound > maxDepth) {
      throw new PluginError('Code nesting too deep');
    }
  }

  /**
   * 在安全环境中执行代码
   */
  private async executeInSafeEnvironment<T>(
    code: string,
    context: Record<string, unknown>,
  ): Promise<T> {
    return new Promise((resolve, reject) => {
      const timeout = setTimeout(() => {
        reject(new PluginError('Execution timeout'));
      }, this.options.timeout);

      try {
        // 创建受限的执行环境
        const safeGlobals = this.createSafeGlobals();
        const safeContext = { ...safeGlobals, ...context };

        // 使用 Function 构造器创建隔离函数
        const paramNames = Object.keys(safeContext);
        const paramValues = Object.values(safeContext);

        // 包装代码以防止访问全局对象
        const wrappedCode = `
          "use strict";
          (function() {
            // 禁用危险的全局对象
            const window = undefined;
            const document = undefined;
            const global = undefined;
            const process = undefined;
            const require = undefined;
            const module = undefined;
            const exports = undefined;
            
            // 执行用户代码
            return (function() {
              ${code}
            })();
          })()
        `;

        const fn = new Function(...paramNames, `return ${wrappedCode}`);
        const result = fn(...paramValues);

        clearTimeout(timeout);
        resolve(result);
      } catch (error) {
        clearTimeout(timeout);
        reject(error);
      }
    });
  }

  /**
   * 创建安全的全局对象
   */
  private createSafeGlobals(): Record<string, unknown> {
    const safeGlobals: Record<string, unknown> = {};

    // 只添加允许的全局对象
    for (const globalName of this.options.allowedGlobals) {
      switch (globalName) {
      case 'console':
        safeGlobals.console = {
          log: (...args: unknown[]) => logger.debug('Plugin log:', ...args),
          warn: (...args: unknown[]) => logger.warn('Plugin warn:', ...args),
          error: (...args: unknown[]) => logger.error('Plugin error:', new Error(String(args[0])), ...args.slice(1)),
        };
        break;
      case 'setTimeout':
        safeGlobals.setTimeout = (fn: () => void, delay: number) => {
          if (delay > 10000) throw new PluginError('Timeout too long');
          return setTimeout(fn, delay);
        };
        break;
      case 'clearTimeout':
        safeGlobals.clearTimeout = clearTimeout;
        break;
      default:
        // 其他安全的全局对象可以在这里添加
        break;
      }
    }

    return safeGlobals;
  }

  /**
   * 获取内存使用情况
   */
  private getMemoryUsage(): number {
    if (typeof performance !== 'undefined' && (performance as any).memory) {
      return (performance as any).memory.usedJSHeapSize;
    }
    return 0;
  }

  /**
   * 清理资源
   */
  destroy(): void {
    if (this.worker) {
      this.worker.terminate();
      this.worker = undefined;
    }
  }
}

/**
 * 创建沙箱实例
 */
export function createSandbox(options?: SandboxOptions): SecureSandbox {
  return new SecureSandbox(options);
}